

#include "Graphics.h"
#include "ElementBuffer.h"
#include "MathDefs.h"
#include "GraphicsDefs.h"
#include <glad/glad.h>
#include <iostream>


ElementBuffer::ElementBuffer(Context* context) :
	Object(context)
{
	vertexSize_ = 1 * 4;
}

ElementBuffer::~ElementBuffer()
{
	Release();
}

void ElementBuffer::SetVertexSize(unsigned size)
{
	vertexSize_ = size;
}

bool ElementBuffer::SetSize(unsigned vertexCount, bool dynamic)
{

	vertexCount_ = vertexCount;
	dynamic_ = dynamic;

	if (vertexCount_ && vertexSize_)
	{
		if (data_)
		{
			delete[] data_;
			data_ = nullptr;
		}
		data_ = new unsigned char[vertexCount_ * vertexSize_];
	}

	return Create();
}

void ElementBuffer::Release()
{
	if (ebo_)
	{
		context_->GetGraphics()->SetEBO(0);
		glDeleteBuffers(1, &ebo_);
		ebo_ = 0;
	}

	if (data_)
	{
		delete[] data_;
		data_ = nullptr;
	}
}

bool ElementBuffer::SetData(const void* data)
{
	if (!data)
	{
		assert(0);
		return false;
	}

	if (!vertexSize_)
	{
		assert(0);
		return false;
	}

	if (data_ && data != data_)
		memcpy(data_, data, vertexCount_ * (size_t)vertexSize_);

	if (ebo_)
	{
		if (context_->GetGraphics())
		{
			context_->GetGraphics()->SetEBO(ebo_);
			glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertexCount_ * (size_t)vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
		}
	}
	return true;
}

bool ElementBuffer::SetDataRange(const void* data, unsigned start, unsigned count, bool discard)
{
	if (start == 0 && count == vertexCount_)
		return SetData(data);

	if (!data)
	{
		assert(0);
		return false;
	}

	if (!vertexSize_)
	{
		assert(0);
		return false;
	}

	if (start + count > vertexCount_)
	{
		assert(0);
		return false;
	}

	if (!count)
		return true;

	if (data_ && data_ + start * vertexSize_ != data)
		memcpy(data_ + start * vertexSize_, data, count * (size_t)vertexSize_);

	if (ebo_)
	{
		if (!context_->GetGraphics())
		{
			context_->GetGraphics()->SetEBO(ebo_);
			if (!discard || start != 0)
				glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start * (size_t)vertexSize_, count * vertexSize_, data);
			else
				glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * (size_t)vertexSize_, data, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
		}
	}

	return true;
}

bool ElementBuffer::Create()
{
	if (!vertexCount_)
	{
		Release();
		return true;
	}

	if (context_->GetGraphics())
	{
		if (!ebo_)
			glGenBuffers(1, &ebo_);
		if (!ebo_)
		{
			assert(0);
			return false;
		}

		context_->GetGraphics()->SetEBO(ebo_);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertexCount_ * (size_t)vertexSize_, nullptr, dynamic_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
	}

	return true;
}

bool ElementBuffer::UpdateToGPU()
{
	if (ebo_ && data_)
		return SetData(data_);
	else
		return false;
}

